package com.micro.center.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.micro.center.dto.RoleDto;
import com.micro.center.entity.SysRoleEntity;
import com.micro.center.entity.SysUserEntity;
import com.micro.center.entity.SysUserRoleRelEntity;
import com.micro.center.mapper.SysRoleMapper;
import com.micro.common.constant.Constant;
import com.micro.common.constant.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author pan.shun
 * @since 2022/7/5 17:01
 */
@Slf4j
@Service
public class SysRoleService extends ServiceImpl<SysRoleMapper, SysRoleEntity> {

    @Autowired
    private SysRoleUserRelService sysRoleUserRelService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private RedisTemplate redisTemplate;

    @SuppressWarnings("unchecked")
    public void refreshUserRoleCache(SysUserEntity userEntity) {
        List<String> roleList = this.getBaseMapper().getRoleListByUserId(userEntity.getId());
        if (!CollectionUtils.isEmpty(roleList)) {
            redisTemplate.opsForValue().set(Constant.CACHE_KEY.ROLE_PREFIX + userEntity.getUserName(), roleList);
        } else {
            redisTemplate.delete(Constant.CACHE_KEY.ROLE_PREFIX + userEntity.getUserName());
        }
    }

    /**
     * 角色授权
     */
    @Transactional(rollbackFor = Exception.class)
    public R addRole(RoleDto roleDto) {
        if (StringUtils.isNotBlank(roleDto.getRoleCodeList())
                ) {
            List<String> roleCode = Arrays.asList(roleDto.getRoleCodeList().split(","));
            LambdaQueryWrapper<SysRoleEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.select(SysRoleEntity::getId);
            queryWrapper.in(SysRoleEntity::getCode, roleCode);
            List<SysRoleEntity> list = this.list(queryWrapper);
            if (!CollectionUtils.isEmpty(list)) {
                List<String> roleIdList = new ArrayList<>(16);
                list.forEach(res -> {
                    roleIdList.add(res.getId());
                });

                List<SysUserRoleRelEntity> roleRelList = new ArrayList<>(16);
                roleIdList.forEach(r -> {
                    SysUserRoleRelEntity roleRel = new SysUserRoleRelEntity();
                    roleRel.setRoleId(r);
                    roleRel.setUserId(roleDto.getUserId());
                    roleRelList.add(roleRel);
                });
                if (!CollectionUtils.isEmpty(roleRelList)) {
                    // 之前的角色关系全部删除
                    LambdaQueryWrapper<SysUserRoleRelEntity> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(SysUserRoleRelEntity::getUserId, roleDto.getUserId());
                    sysRoleUserRelService.remove(wrapper);

                    // 将新的角色关系建立
                    sysRoleUserRelService.saveBatch(roleRelList);

                    // 根据用户登录状态确定是否刷新一下缓存
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                        // 这个事务表示在前面完成事务提交后在执行刷新缓存的异步提交
                        @Override
                        public void afterCommit() {
                            refreshCache(roleDto.getUserId());
                        }
                    });
                }
            }
            return R.success("角色授权成功");
        } else {
            roleDto.setRoleCodeList(Constant.ROLE.ADMIN + "," + Constant.ROLE.USER);
            this.removeRole(roleDto);
            return R.success();
        }
    }

    /**
     * 角色解权
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public R removeRole(RoleDto roleDto) {
        if (StringUtils.isNotBlank(roleDto.getUserId())
                && StringUtils.isNotBlank(roleDto.getRoleCodeList())
                ) {

            String roleCodeString = roleDto.getRoleCodeList();

            List<String> roleCodeList = Arrays.asList(roleCodeString.split(","));


            LambdaQueryWrapper<SysRoleEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(SysRoleEntity::getId);
            wrapper.in(SysRoleEntity::getCode, roleCodeList);
            List<SysRoleEntity> list = this.list(wrapper);
            if (!CollectionUtils.isEmpty(list)) {
                List<String> roleIdList = new ArrayList<>(16);
                list.forEach(res -> roleIdList.add(res.getId()));

                LambdaQueryWrapper<SysUserRoleRelEntity> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.in(SysUserRoleRelEntity::getRoleId, roleIdList);
                queryWrapper.eq(SysUserRoleRelEntity::getUserId, roleDto.getUserId());
                sysRoleUserRelService.remove(queryWrapper);

                // 缓存刷新
                TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                    // 这个事务表示在前面完成事务提交后在执行刷新缓存的异步提交
                    @Override
                    public void afterCommit() {
                        refreshCache(roleDto.getUserId());
                    }
                });
            }
            return R.success("用户解除角色关联成功");
        } else {
            return R.error("角色编码不能为空");
        }
    }

    /**
     * 刷新缓存
     */
    @SuppressWarnings("unchecked")
    @Async
    public void refreshCache(String userId) {
        SysUserEntity user = sysUserService.getById(userId);
        if (user == null) {
            log.error("用户ID {} 不存在 ", userId);
            return;
        }
        refreshUserRoleCache(user);
    }

    public R getRoleByUserName(String userId) {
        List<String> roleNameByUserId = this.baseMapper.getRoleNameByUserId(userId);
        return R.success(roleNameByUserId);
    }
}
